package com.netease.nie.facade;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.netease.nie.base.cache.redis.Redis;
import com.netease.nie.base.exceptions.BusinessException;
import com.netease.nie.base.utils.JsonUtils;
import com.netease.nie.base.utils.PageUtils;
import com.netease.nie.common.CommonBusinessTools;
import com.netease.nie.constants.BusinessConstants;
import com.netease.nie.constants.CachePrefixConstants;
import com.netease.nie.constants.CommonConstants;
import com.netease.nie.constants.DisplayTypeConstants;
import com.netease.nie.dto.ColumnGoodsSnapshotDto;
import com.netease.nie.dto.ExchangeGoodsInfoListDto;
import com.netease.nie.model.ColumnInfo;
import com.netease.nie.service.ColumnInfoGoodsService;
import com.netease.nie.service.ColumnInfoService;
import com.netease.nie.service.CreditService;

/**
 * 
 * @author KingsHunter
 * @createDate June 30th,2016
 * 
 */
@Service
public class ColumnGoodsFacadeImpl extends CommonBusinessTools implements ColumnGoodsFacade {

	private static final String COLUMN_INFO_TOP_GOODS_LIST_PREFIX = CachePrefixConstants.ColumnPrefix.COLUMN_INFO_TOP_GOODS_LIST_PREFIX;
	private static final String COLUMN_INFO_GOODS_LIST_PREFIX = CachePrefixConstants.GoodsPrefix.COLUMN_INFO_GOODS_LIST_PREFIX;
	private static final String GOODS_STOCK_PREFIX = CachePrefixConstants.GoodsPrefix.GOODS_STOCK_PREFIX;
	private static final String COLUMN_INFO_LIST_KEY = "Column_Info_List";
	private static final String USER_COLUMN_INFO_LIST_PREFIX = CachePrefixConstants.CustomPrefix.USER_COLUMN_INFO_LIST_PREFIX;
	private static final int LIST_SIZE = CommonConstants.LIST_SIZE;
	private static final int PAGE_SIZE = 20;
	
	@Autowired
	private ColumnInfoService columnInfoService;
	
	@Autowired
	private ColumnInfoGoodsService columnInfoGoodsService;
	
	@Autowired
	private CreditService creditService;
	
	@Autowired
	private Redis redis;
	
	public List<ColumnGoodsSnapshotDto> listAllColumnGoodsSnapshotDto(
			Long userId, int page) {
		if (userId <= 0)
			throw new BusinessException(BusinessConstants.INVALID_USER_ID.getCode(), BusinessConstants.INVALID_USER_ID.getMsg());
		List<ColumnGoodsSnapshotDto> columnGoodsSnapshotDtos = new ArrayList<>();
		ColumnGoodsSnapshotDto columnGoodsSnapshotDto = null;
		//获取栏目信息
		int pageStartIndex = PageUtils.getPageStartIndex(page, PAGE_SIZE);
		int pageEndIndex = PageUtils.getPageEndIndex(page, PAGE_SIZE);
		String columnInfoListKey = COLUMN_INFO_LIST_KEY;
		boolean exists = redis.exists(COLUMN_INFO_LIST_KEY);
		List<ColumnInfo> columnInfoList = null;
		if (!exists) {
			columnInfoList = columnInfoService.queryAllColumnInfo();
			if (CollectionUtils.isNotEmpty(columnInfoList))
				redis.rpush(columnInfoListKey, columnInfoList);
		} else {
			columnInfoList = redis.lrange(columnInfoListKey, pageStartIndex, pageEndIndex, ColumnInfo.class);
			if (CollectionUtils.isEmpty(columnInfoList))
				return Collections.emptyList();
		}
		List<Integer> userColumnIdList = generateCustomColumnInfoId(userId);
		int level = creditService.queryUserCreditLevelByUserId(userId);
		
		filterColumnInfoList(columnInfoList, userColumnIdList, level);
		fillColunInfo2ListColumnGoodsSnapshotDtoList(columnGoodsSnapshotDtos, columnInfoList, DisplayTypeConstants.WAP.getCode());
		
		//获取栏目内的商品信息
		ExchangeGoodsInfoListDto exchangeGoodsInfoListDto = null;
		List<ExchangeGoodsInfoListDto> exchangeGoodsInfoListDtoList = null;
		List<Integer> uselessColumnInfoIds = findUselessColumnInfoGoodsListId(columnInfoList);
		if (!uselessColumnInfoIds.isEmpty()) {
			exchangeGoodsInfoListDtoList = columnInfoGoodsService.queryGoodsInfoListByColumnInfoIds(uselessColumnInfoIds);
			fillColumnInfoGoodsListCache(exchangeGoodsInfoListDtoList);
		} else {
			exchangeGoodsInfoListDtoList = new ArrayList<>();
			fillColumnInfoGoodsList(exchangeGoodsInfoListDtoList, columnInfoList);
		}
		
		//获取实时库存
		int exchangeGoodsInfoListDtoListSize = exchangeGoodsInfoListDtoList.size();
		String[] exchangeGoodsStockKeys = {};
		String exchangeGoodsStockKey = null;
		for (int i = 0; i < exchangeGoodsInfoListDtoListSize; i++) {
			exchangeGoodsInfoListDto = exchangeGoodsInfoListDtoList.get(i);
			exchangeGoodsStockKey = GOODS_STOCK_PREFIX + exchangeGoodsInfoListDto.getId();
			exchangeGoodsStockKeys = (String[]) ArrayUtils.add(exchangeGoodsStockKeys, exchangeGoodsStockKey);
		}
		
		if (exchangeGoodsStockKeys.length > 0) {
			List<String> strList = redis.mget(exchangeGoodsStockKeys);
			Map<Integer, Integer> exchangeGoodsStockMap = distillGoodsStock(exchangeGoodsStockKeys, strList);
			for (int i = 0; i < exchangeGoodsInfoListDtoListSize; i++) {
				exchangeGoodsInfoListDto = exchangeGoodsInfoListDtoList.get(i);
				Integer stock = exchangeGoodsStockMap.get(exchangeGoodsInfoListDto.getId());
				if (stock != null) {
					exchangeGoodsInfoListDto.setStock(stock);
				}
			}
		}
		
		//替换商品图片
		replaceGoodsInfoListDtoThumbnailUrl(exchangeGoodsInfoListDtoList, DisplayTypeConstants.WAP.getCode());
		
		//组装列表结果
		Map<Integer, List<ExchangeGoodsInfoListDto>> map = transferCoGoodsListDtos(exchangeGoodsInfoListDtoList);
		int columnGoodsSnapshotDtosSize = columnGoodsSnapshotDtos.size();
		for (int i = 0; i < columnGoodsSnapshotDtosSize; i++) {
			columnGoodsSnapshotDto = columnGoodsSnapshotDtos.get(i);
			int columnId = columnGoodsSnapshotDto.getId();
			if (map.containsKey(columnId)) {
				columnGoodsSnapshotDto.setExchangeGoodsInfoListDtoList(map.get(columnId));
			}
		}
		
		return columnGoodsSnapshotDtos;
	}
	
	/**
	 * 过滤标签库栏目和vip记录
	 * @param columnInfoList
	 */
	private void filterColumnInfoList(List<ColumnInfo> columnInfoList, List<Integer> userColumnIdList, int level) {
		if (columnInfoList != null && !columnInfoList.isEmpty()) {
			ColumnInfo columnInfo = null;
			//用户推荐栏目为空
			if (userColumnIdList.isEmpty()) {
				Iterator<ColumnInfo> iterator = columnInfoList.iterator();
				while (iterator.hasNext()) {
					columnInfo = iterator.next();
					if (columnInfo.getTags() == 0)
						iterator.remove();
					else if (StringUtils.isNotBlank(columnInfo.getLevels())) {
						if (columnInfo.getLevels().indexOf(String.valueOf(level)) == -1) {
							iterator.remove();
						}
					}
				}
			} else {
				Iterator<ColumnInfo> iterator = columnInfoList.iterator();
				while(iterator.hasNext()) {
					columnInfo = iterator.next();
					int columnInfoId = columnInfo.getId();
					if (columnInfo.getTags() == 1) {
						if (!userColumnIdList.contains(columnInfoId))
							iterator.remove();
					}
					else if (StringUtils.isNotBlank(columnInfo.getLevels())) {
						if (columnInfo.getLevels().indexOf(String.valueOf(level)) == -1) {
							iterator.remove();
						}
					}
				}
			}
		}
	}
	
	/**
	 * 查找栏目商品列表缓存key失效的栏目id
	 * @param columnInfoList
	 * @return
	 */
	private List<Integer> findUselessColumnInfoGoodsListId(List<ColumnInfo> columnInfoList) {
		if (columnInfoList != null && !columnInfoList.isEmpty()) {
			ColumnInfo columnInfo = null;
			String columnInfoGoodsListKey = null;
			int columnInfoListSize = columnInfoList.size();
			List<Integer> columnInfoIds = new ArrayList<>();
			for (int i = 0; i < columnInfoListSize; i++) {
				columnInfo = columnInfoList.get(i);
				columnInfoGoodsListKey = COLUMN_INFO_TOP_GOODS_LIST_PREFIX + columnInfo.getId();
				boolean exists = redis.exists(columnInfoGoodsListKey);
				if (!exists)
					columnInfoIds.add(columnInfo.getId());
			}
			
			return columnInfoIds;
		}
		return Collections.emptyList(); 
	}
	
	private void fillColumnInfoGoodsListCache(List<ExchangeGoodsInfoListDto> exchangeGoodsInfoListDtoList) {
		if (exchangeGoodsInfoListDtoList != null && !exchangeGoodsInfoListDtoList.isEmpty()) {
			Map<String, String[]> map = new HashMap<String, String[]>();
			ExchangeGoodsInfoListDto exchangeGoodsInfoListDto = null;
			String columnInfoGoodsListKey = null;
			int exchangeGoodsInfoListDtoListSize = exchangeGoodsInfoListDtoList.size();
			String[] exchangeGoodsInfoListDtoArr = {};
			for (int i = 0; i < exchangeGoodsInfoListDtoListSize; i++) {
				exchangeGoodsInfoListDto = exchangeGoodsInfoListDtoList.get(i);
				int columnId = exchangeGoodsInfoListDto.getColumnId();
				columnInfoGoodsListKey = COLUMN_INFO_TOP_GOODS_LIST_PREFIX + columnId;
				if (map.containsKey(columnInfoGoodsListKey))
					exchangeGoodsInfoListDtoArr = map.get(columnInfoGoodsListKey);
				else
					exchangeGoodsInfoListDtoArr = ArrayUtils.EMPTY_STRING_ARRAY;
				exchangeGoodsInfoListDtoArr = (String[]) ArrayUtils.add(exchangeGoodsInfoListDtoArr, JsonUtils.obj2String(exchangeGoodsInfoListDto));
				map.put(columnInfoGoodsListKey, exchangeGoodsInfoListDtoArr);
			}
			
			for (Entry<String, String[]> entry : map.entrySet())
				redis.rpush(entry.getKey(), entry.getValue());
		}
	}
	
	private void fillColumnInfoGoodsList(List<ExchangeGoodsInfoListDto> exchangeGoodsInfoListDtoList, List<ColumnInfo> columnInfoList) {
		if (columnInfoList != null && !columnInfoList.isEmpty()) {
			int columnInfoListSize = columnInfoList.size();
			String columnInfoGoodsListKey = null;
			List<String> strList = null;
			ColumnInfo columnInfo = null;
			ExchangeGoodsInfoListDto exchangeGoodsInfoListDto = null;
			List<String> allStrList = new ArrayList<>();
			for (int i = 0; i < columnInfoListSize; i++) {
				columnInfo = columnInfoList.get(i);
				columnInfoGoodsListKey = COLUMN_INFO_TOP_GOODS_LIST_PREFIX + columnInfo.getId();
				int normalDisplayCount = columnInfo.getNormalDisplayCount();
				strList = redis.lrange(columnInfoGoodsListKey, 0, --normalDisplayCount);
				if (strList != null && !strList.isEmpty()) {
					allStrList.addAll(strList);
				}
			}
			
			String text = null;
			int allStrListSize = allStrList.size();
			for (int i = 0; i < allStrListSize; i++) {
				text = allStrList.get(i);
				if (StringUtils.isNotBlank(text)) {
					exchangeGoodsInfoListDto = JsonUtils.getClazz(text, ExchangeGoodsInfoListDto.class);
					exchangeGoodsInfoListDtoList.add(exchangeGoodsInfoListDto);
				}
			}
		}
	}
	
	private List<Integer> generateCustomColumnInfoId(long userId) {
		String userColumnInfoKey = USER_COLUMN_INFO_LIST_PREFIX + userId;
		boolean exists = redis.exists(userColumnInfoKey);
		if (exists) {
			List<Integer> userColumnIdList = new ArrayList<>();
			List<String> strList = redis.lrange(userColumnInfoKey, 0, -1);
			if (strList != null && strList.isEmpty()) {
				int strListSize = strList.size();
				String text = null;
				for (int i = 0; i < strListSize; i++) {
					text = strList.get(i);
					if (StringUtils.isNotBlank(text)) {
						int columnInfoId = Integer.valueOf(text);
						userColumnIdList.add(columnInfoId);
					}
				}
				return userColumnIdList;
			}
		}
		return Collections.emptyList();
	}
	
	public List<ExchangeGoodsInfoListDto> listGoodsInfoDtoByColumnInfoId(
			int columnId, int page, Long userId) {		
		int pageStartIndex = PageUtils.getPageStartIndex(page);
		int pageEndIndex = PageUtils.getPageEndIndex(page);
		List<ExchangeGoodsInfoListDto> exchangeGoodsInfoListDtoList = null;
		ExchangeGoodsInfoListDto exchangeGoodsInfoListDto = null;
		if (page > 2) {
			exchangeGoodsInfoListDtoList = columnInfoGoodsService.queryGoodsInfoListByColumnInfoId(columnId, pageStartIndex, PAGE_SIZE);
			if (exchangeGoodsInfoListDtoList == null || exchangeGoodsInfoListDtoList.isEmpty())
				return Collections.emptyList();
		} else {
			String columnInfoGoodsListKey = COLUMN_INFO_GOODS_LIST_PREFIX + columnId;
			boolean exists = redis.exists(columnInfoGoodsListKey);
			if (!exists) {
				exchangeGoodsInfoListDtoList = columnInfoGoodsService.queryGoodsInfoListByColumnInfoId(columnId, 0, LIST_SIZE);
				if (CollectionUtils.isNotEmpty(exchangeGoodsInfoListDtoList)) {
					redis.rpush(columnInfoGoodsListKey, exchangeGoodsInfoListDtoList);
					exchangeGoodsInfoListDtoList = PageUtils.getPageListByIndex(exchangeGoodsInfoListDtoList, pageStartIndex, pageEndIndex);
				}
			} else {
				exchangeGoodsInfoListDtoList = redis.lrange(columnInfoGoodsListKey, pageStartIndex, --pageEndIndex, ExchangeGoodsInfoListDto.class);
				if (CollectionUtils.isEmpty(exchangeGoodsInfoListDtoList))
					return Collections.emptyList();
			}
			
			//获取实时库存
			int exchangeGoodsInfoListDtoListSize = exchangeGoodsInfoListDtoList.size();
			String[] goodsStockKeys = {};
			String goodsStockKey = null;
			for (int i = 0; i < exchangeGoodsInfoListDtoListSize; i++) {
				exchangeGoodsInfoListDto = exchangeGoodsInfoListDtoList.get(i);
				goodsStockKey = GOODS_STOCK_PREFIX + exchangeGoodsInfoListDto.getId();
				goodsStockKeys = (String[]) ArrayUtils.add(goodsStockKeys, goodsStockKey);
			}
			
			if (goodsStockKeys.length > 0) {
				List<String> strList = redis.mget(goodsStockKeys);
				Map<Integer, Integer> goodsStockMap = distillGoodsStock(goodsStockKeys, strList);
				for (int i = 0; i < exchangeGoodsInfoListDtoListSize; i++) {
					exchangeGoodsInfoListDto = exchangeGoodsInfoListDtoList.get(i);
					Integer stock = goodsStockMap.get(exchangeGoodsInfoListDto.getId());
					if (stock != null) {
						exchangeGoodsInfoListDto.setStock(stock);
					}
				}
			}
		}
		
		//替换商品图片
		replaceGoodsInfoListDtoThumbnailUrl(exchangeGoodsInfoListDtoList, DisplayTypeConstants.WAP.getCode());
		return exchangeGoodsInfoListDtoList;
	}

}
